// Package cloud 实现了云服务连接管理
package cloud

import (
	"context"
	"fmt"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/logger"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
)

// ConnectionManager 连接管理器
type ConnectionManager struct {
	systemConfig map[string]interface{}
	mqttClient   *MQTTClient
	wg           sync.WaitGroup
	stopChan     chan struct{}
	isConnected  bool
	sync.RWMutex
}

// NewConnectionManager 创建连接管理器
func NewConnectionManager(systemConfig map[string]interface{}) (*ConnectionManager, error) {
	cm := &ConnectionManager{
		systemConfig: systemConfig,
		stopChan:     make(chan struct{}),
	}

	// 创建MQTT客户端
	mqttClient, err := NewMQTTClient(systemConfig)
	if err != nil {
		return nil, fmt.Errorf("创建MQTT客户端失败: %w", err)
	}

	cm.mqttClient = mqttClient
	return cm, nil
}

// Start 启动连接管理器
func (c *ConnectionManager) Start(ctx context.Context) error {
	// 启动MQTT客户端
	if err := c.mqttClient.Connect(); err != nil {
		return fmt.Errorf("MQTT连接失败: %w", err)
	}

	// 监听上下文取消信号
	c.wg.Add(1)
	go func() {
		defer c.wg.Done()
		select {
		case <-ctx.Done():
			logger.SystemInfo("收到退出信号，开始关闭连接管理器")
			c.Stop()
		case <-c.stopChan:
			return
		}
	}()

	c.Lock()
	c.isConnected = true
	c.Unlock()

	logger.SystemInfo("连接管理器启动成功")
	return nil
}

// Stop 停止连接管理器
func (c *ConnectionManager) Stop() {
	c.Lock()
	if !c.isConnected {
		c.Unlock()
		return
	}
	c.isConnected = false
	c.Unlock()

	// 关闭停止信号通道
	select {
	case <-c.stopChan:
		// 通道已关闭，不需要再次关闭
	default:
		close(c.stopChan)
	}

	// 等待所有协程退出
	done := make(chan struct{})
	go func() {
		c.wg.Wait()
		close(done)
	}()

	// 设置超时时间
	select {
	case <-done:
		logger.SystemInfo("所有协程已正常退出")
	case <-time.After(5 * time.Second):
		logger.SystemWarn("等待协程退出超时")
	}

	// 断开MQTT连接
	if c.mqttClient != nil {
		logger.SystemInfo("正在断开MQTT连接")
		c.mqttClient.Disconnect()
	}

	logger.SystemInfo("连接管理器已停止")
}

// PublishMQTT 发布MQTT消息
func (c *ConnectionManager) PublishMQTT(topic, payload string) error {
	if !c.IsConnected() {
		return fmt.Errorf("MQTT未连接")
	}
	return c.mqttClient.Publish(topic, payload)
}

// SubscribeMQTT 订阅MQTT主题
func (c *ConnectionManager) SubscribeMQTT(topic string, handler func(string)) error {
	if !c.IsConnected() {
		return fmt.Errorf("MQTT未连接")
	}

	mqttHandler := func(client mqtt.Client, msg mqtt.Message) {
		handler(string(msg.Payload()))
	}

	if err := c.mqttClient.subscribe(topic, mqttHandler); err != nil {
		return fmt.Errorf("MQTT订阅失败: %w", err)
	}

	logger.SystemDebug("MQTT订阅成功", zap.String("topic", topic))
	return nil
}

// UnsubscribeMQTT 取消订阅MQTT主题
func (c *ConnectionManager) UnsubscribeMQTT(topic string) error {
	if !c.IsConnected() {
		return fmt.Errorf("MQTT未连接")
	}

	if err := c.mqttClient.unsubscribe(topic); err != nil {
		return fmt.Errorf("MQTT取消订阅失败: %w", err)
	}

	logger.SystemDebug("MQTT取消订阅成功", zap.String("topic", topic))
	return nil
}

// IsConnected 获取连接状态
func (c *ConnectionManager) IsConnected() bool {
	c.RLock()
	defer c.RUnlock()
	return c.isConnected && c.mqttClient != nil && c.mqttClient.IsConnected()
}

// UpdateConfig 更新连接管理器配置
func (c *ConnectionManager) UpdateConfig(newConfig map[string]interface{}) error {
	c.Lock()
	defer c.Unlock()

	// 保存新配置
	c.systemConfig = newConfig

	// 检查MQTT配置是否发生变化
	brokerChanged := false
	clientIDChanged := false

	// 获取新旧配置中的MQTT参数
	oldBroker := c.mqttClient.GetBrokerURL()
	oldClientID := c.mqttClient.GetClientID()

	newBroker, ok := newConfig["mqtt.broker_address"].(string)
	if ok && newBroker != oldBroker {
		brokerChanged = true
	}

	newClientID, ok := newConfig["mqtt.client_id"].(string)
	if ok && newClientID != oldClientID {
		clientIDChanged = true
	}

	// 如果关键参数发生变化，需要重新连接
	if brokerChanged || clientIDChanged {
		logger.SystemInfo("MQTT配置发生变化，重新连接",
			zap.Bool("brokerChanged", brokerChanged),
			zap.Bool("clientIDChanged", clientIDChanged))

		// 断开旧连接
		c.mqttClient.Disconnect()

		// 创建新的MQTT客户端
		mqttClient, err := NewMQTTClient(newConfig)
		if err != nil {
			return fmt.Errorf("创建MQTT客户端失败: %w", err)
		}

		// 连接新客户端
		if err := mqttClient.Connect(); err != nil {
			return fmt.Errorf("MQTT连接失败: %w", err)
		}

		// 更新客户端引用
		c.mqttClient = mqttClient
		logger.SystemInfo("MQTT客户端已重新连接")
	} else {
		// 其他非关键参数的更新
		logger.SystemInfo("MQTT配置更新，但无需重新连接")
	}

	return nil
}
